#include "FifoLectura.h"
#include <BaseException.h>
#include <cstring>
#include <errno.h>
#include <sstream>


FifoLectura::FifoLectura(): Fifo(ProjectId::FIFO_LECTURA) {
}

FifoLectura::FifoLectura(const std::string nombre, const int modoCreacion, const bool protectAccess)
: Fifo(nombre, modoCreacion, ProjectId::FIFO_LECTURA, protectAccess) {
}

FifoLectura::~FifoLectura() {
}

void FifoLectura::abrir() {
	if(fd > 0)
		throw BaseException("El fifo ya se encuentra abierto");
	
	fd = open ( m_Nombre.c_str(),O_RDONLY );
	
	if(fd < 0)
	{
		std::stringstream eMsg("Ocurrio un error al abrir el fifo "+m_Nombre);
		eMsg << "Error " << errno << ":" << strerror(errno);
		throw BaseException(eMsg.str(), errno);
	}
}

void FifoLectura::leer(void* buffer,const ssize_t buffsize) {
	if(fd < 0)
		throw BaseException("El fifo no se encuentra abierto");
	
	ssize_t cantBytesLeidos = 1;
	ssize_t cantBytesRestantes = buffsize;
	char* bufferAux = static_cast<char*> (buffer);
	
	while(cantBytesRestantes > 0 && cantBytesLeidos > 0)
	{
		cantBytesLeidos = read ( fd, bufferAux, cantBytesRestantes );
		if(cantBytesLeidos < 0)
		{
			// Si me interrumpieron, verifico si es para salir o si debo continuar
			if (errno == EINTR && !this->mustExit()) 
				continue;
			std::stringstream eMsg("Ocurrio un error al leer del fifo");
			eMsg << "Error " << errno << ":" << strerror(errno);
			throw BaseException(eMsg.str(), errno);
		}
		bufferAux += cantBytesLeidos;
		cantBytesRestantes -= cantBytesLeidos;
		this->decrementarBytesContenidos(cantBytesLeidos);
	}
	
	if(cantBytesRestantes > 0)
	{
		std::stringstream eMsg;
		if(cantBytesLeidos == 0)
		{
			eMsg << "El fifo no se encuentra abierto para escritura.";
		}
		else
		{
			eMsg << "No se pudo leer la cantidad de bytes requerida.";
			eMsg << "Se requieren " << buffsize << " pero faltan recibir " << cantBytesRestantes;
		}
		throw BaseException(eMsg.str());
	}
}

void FifoLectura::leerSincronizado(void* buffer,const ssize_t buffsize) {
	if(fd < 0)
		throw BaseException("El fifo no se encuentra abierto");
	
	ssize_t cantBytesLeidos = 1;
	ssize_t cantBytesRestantes = buffsize;
	char* bufferAux = static_cast<char*> (buffer);
	
	this->lock();
	while(cantBytesRestantes > 0 && cantBytesLeidos > 0)
	{
		cantBytesLeidos = read ( fd, bufferAux, cantBytesRestantes );
		if(cantBytesLeidos < 0)
		{
			// Si me interrumpieron, verifico si es para salir o si debo continuar
			if (errno == EINTR && !this->mustExit()) 
				continue;
			this->unlock();
			std::stringstream eMsg("Ocurrio un error al leer del fifo");
			eMsg << "Error " << errno << ":" << strerror(errno);
			throw BaseException(eMsg.str(), errno);
		}
		bufferAux += cantBytesLeidos;
		cantBytesRestantes -= cantBytesLeidos;
		this->decrementarBytesContenidos(cantBytesLeidos);
	}
	this->unlock();
	
	if(cantBytesRestantes > 0)
	{
		std::stringstream eMsg;
		if(cantBytesLeidos == 0)
		{
			eMsg << "El fifo no se encuentra abierto para escritura.";
		}
		else
		{
			eMsg << "No se pudo leer la cantidad de bytes requerida.";
			eMsg << "Se requieren " << buffsize << " pero faltan recibir " << cantBytesRestantes;
		}
		throw BaseException(eMsg.str());
	}
}

void FifoLectura::cerrarRecepcion()
{
	Fifo::cerrarRecepcion();
}
